home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / 80x0393.zip / CHGLN_2.ASM < prev    next >
Assembly Source File  |  1993-03-30  |  10KB  |  292 lines

  1. comment    *
  2.  
  3.         Author: Yousuf J. Khan
  4.  
  5.         Purpose: A TSR which will detect if a diskette has been changed,
  6.         even if that drive's diskette change detection line is out of
  7.         commission. Normally only used by 5.25" HD drives which have
  8.         trouble recognizing a different density diskette.
  9.  
  10.     *
  11.  
  12. .model tiny
  13.  
  14. bds     segment at 40h
  15.  
  16.         comment {
  17.  
  18.         The BIOS Data Segment, segment 40h. All diskette related status
  19.         bytes are listed below.
  20.  
  21.                 {
  22.  
  23.         org     3Eh
  24. disk_recal_stat db      ?       ;diskette recalibrate status
  25. disk_motor_stat db      ?       ;diskette motor status
  26. motor_timeout   db      ?       ;diskette motor turn-off timeout count
  27. last_op         db      ?       ;last operation's error message
  28. statcombytes    db      7 dup(?);status and command bytes
  29.         org     8Bh
  30. media_control   db      ?       ;diskette media control byte
  31.         org     8Fh
  32. ctrlr_info      db      ?       ;diskette controller info
  33. drive0          db      ?       ;diskette 0 (A:) media state
  34. drive1          db      ?       ;diskette 1 (B:) media state
  35. last_drive0     db      ?       ;prior diskette 0 media state
  36. last_drive1     db      ?       ;prior diskette 1 media state
  37. cur_trak0       db      ?       ;current track, drive 0
  38. cur_trak1       db      ?       ;current track, drive 1
  39.         ends
  40.  
  41. .code
  42.  
  43.         comment {
  44.  
  45.         Look in the first byte of the first FCB field of PSP to get
  46.         drive letter. This field takes any command-line argument that
  47.         looks like a drive letter and converts it into an integer (eg.
  48.         1=A:, 2=B:, etc.).
  49.  
  50.                 {
  51.  
  52.         org     5Ch
  53. FCB     db      ?       ;first FCB field of PSP
  54.         org     100h
  55.  
  56. .startup
  57.         jmp     tsr_init        ;jump to transient portion
  58.  
  59.         comment {
  60.  
  61.         Save data that is required for the resident portion of TSR here.
  62.         Any other data not required to be resident can go into regular
  63.         old '.data' segment.
  64.  
  65.                 {
  66.  
  67. old_vect        dw      ?,?     ;address of previous level ISR
  68. old_ax          dw      ?
  69. old_bx          dw      ?
  70. old_ds          dw      ?
  71. old_es          dw      ?
  72. old_si          dw      ?
  73.  
  74. new_int13:
  75.  
  76.         comment {
  77.  
  78.         When Int 13h called, can only assume CS:IP is saved therefore
  79.         must manually save all other segments and registers.
  80.  
  81.                 {
  82.  
  83.         ;
  84.         ;let DS:=CS
  85.         ;
  86.         push    ds              ;save DS to be restored upon exit
  87.         push    ax
  88.         mov     ax, cs
  89.         mov     ds, ax          ;make DS equal to CS
  90.         pop     ax
  91.         ;
  92.         ;See if an access was made to our diskette drive? If not, then
  93.         ;let it pass through.
  94.         ;
  95.         push    dx
  96.         mov     dh, [fcb]
  97.         dec     dh              ;BIOS_drive=FCB_drive-1
  98.         cmp     dl, dh          ;is it drive we're interested in?
  99.         pop     dx
  100.         jne     passthru        ;not drive we're interested in
  101.         ;
  102.         ;See if an access to the read, write, or verify functions were
  103.         ;made (ie. subfuncs 2 to 4)? If it was then intercept. Otherwise
  104.         ;let it pass through.
  105.         ;
  106.         cmp     ah, 4
  107.         ja      passthru        ;greater than subfnct 4
  108.         cmp     ah, 2
  109.         jb      passthru        ;less than subfnct 2
  110.         ;
  111.         ;save AX in case fnct has to be recalled
  112.         ;
  113.         mov     [old_ax], ax    
  114.         ;
  115.         ;call old INT 13h:
  116.         ;simulate an INT by pushing FLAGS before CALLing
  117.         ;
  118.         pushf           
  119.         call    dword ptr [old_vect]
  120.         ;
  121.         ;If no errors were found, then there is no need to redo this
  122.         ;function. Just jump to the end.
  123.         ;
  124.         pushf   ;save the flag for exit from ISR
  125.         jnc     simulated_iret
  126.  
  127.         comment {
  128.  
  129.         If an "address mark not found" error (ie. error #2) was
  130.         returned, then modify various diskette parameters in BIOS data
  131.         segment byte and redo function again.
  132.  
  133.                 {
  134.  
  135.         cmp     ah, 2
  136.         jne     simulated_iret  ;it wasn't an error #2
  137.         popf                    ;pop exit ISR flag & discard
  138.         ;
  139.         ;ES:=BIOS Data Segment
  140.         ;
  141.         int     3               ;debugger breakpoint
  142.         mov     [old_bx], bx
  143.         mov     [old_es], es
  144.         mov     [old_si], si
  145.         mov     bx, BDS
  146.         mov     es, bx
  147.         assume  es:BDS
  148.         ;
  149.         ;SI+BX will be equal to either 90h or 91h, the offset within the
  150.         ;BIOS data segment for either the drive 0 or drive 1 media
  151.         ;state. The FCB number determines whether we want drive 0 or 1.
  152.         ;
  153.         xor     bx, bx  ;make sure BX is zero
  154.         mov     si, offset ctrlr_info
  155.         mov     bl, [fcb]
  156.         ;
  157.         ;To indicate an undetermined drive, set the proper media state
  158.         ;byte to the value 2.
  159.         ;
  160.         mov     byte ptr es:[si][bx], 2
  161.         mov     si, [old_si]
  162.         mov     es, [old_es]
  163.         mov     bx, [old_bx]
  164.         mov     ax, [old_ax]    ;restore AX before recalling function
  165.  
  166. passthru:
  167.         ;
  168.         ;call old INT 13h:
  169.         ;simulate an INT by pushing FLAGS before CALLing
  170.         ;
  171.         pushf           
  172.         call    dword ptr [old_vect]
  173.         pushf           ;save the flag for exit from ISR
  174. simulated_iret:
  175. ;        popf            ;pop the flag for exit from ISR
  176. ;        pop     ds      ;restore original DS
  177. ;        retf    2       ;pop CS,IP, but discard saved entry flag
  178. ;
  179. ;  BINGO! this should be an iret, the old flags never get popped
  180. ;  from the stack.  On my machine with DOS 5.0 and about 20 or so
  181. ;  files on the floppy, it didnt give me any errors after 100 tries.
  182. ;  Why?  DOS resets the stack frame for each call, but for another
  183. ;  parent it will cause a problem.
  184. ;
  185. ;  when at  'retf  2'  the stack looks like this:
  186. ;    ss:[sp+00] = callers cs
  187. ;    ss:[sp+02] = callers ip
  188. ;    ss:[sp+04] = callers flags  ( flags get pushed 1st with int instruction )
  189. ;
  190. ;  What has been happening is that the flags being returned had the correct
  191. ;  return codes, and we returned to the correct cs:ip, however the stack
  192. ;  frame is off by one word on each call by not popping off the flags,
  193. ;  thus screwing with the callers stack frame.  That's why we do a pushf
  194. ;  before a far call to the original interrupt vector.  So, changing the
  195. ;  flags is okay because for this interrupt it is the return code,  however
  196. ;  we must exit in a way to perserve/restore the callers stack frame.
  197. ;
  198. ;  To do the least amount of changes to your code, try replacing with:
  199. ;
  200. ;    simulated_iret:
  201.           pop     ds          ; pop saved flags into DS, DS is still stacked
  202.           push    bp          ; save BP, we need it as an index into the stack
  203.           mov     bp,sp       ; bp = stack pointer,  so  [bp+00] = old bp
  204.           mov     [bp+08],ds  ; edit return flags, cs=[sp+04] so flags=[sp+08]
  205.           pop     bp          ; restore original BP
  206.           pop     ds          ; restore original DS, now [sp+00] = cs
  207.           iret                ; int return
  208.  
  209. ; I compiled this as is, and ran it in a continous loop from a batch file
  210. ; for about 30 minutes with no errors.  Now I have to go clean my floppy
  211. ; drive heads.
  212.  
  213. tsr_init:
  214.  
  215.         comment {
  216.  
  217.         This is the transient portion of the TSR. It initializes the
  218.         resident portion by parsing the command-line, and revectoring
  219.         the interrupts. This entire portion will disappear after
  220.         residency.
  221.  
  222.                 {
  223.  
  224.         .data
  225. CR_LF   equ     13,10
  226. copyright       db      "CHNGLINE (c) 1993, Yousuf J. Khan",cr_lf,"$"
  227. installed       db      "installed",cr_lf,"$"
  228.         .code
  229.         ;
  230.         ;write copyright message
  231.         ;
  232.         mov     ah, 9
  233.         mov     dx, offset copyright
  234.         int     21h
  235.         ;
  236.         ;get command-line
  237.         ;
  238.         cmp     [fcb], 0        ;any command-line argument at all?
  239.         je      install_erro